package net.kornan.framework.network; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HTTP; import com.android.volley.AuthFailureError; import com.android.volley.Request; import com.android.volley.Request.Method; import com.android.volley.toolbox.HttpClientStack.HttpPatch; import com.android.volley.toolbox.HurlStack; public class MultiPartStack extends HurlStack { @SuppressWarnings("unused") private static final String TAG = MultiPartStack.class.getSimpleName(); private final static String HEADER_CONTENT_TYPE = "Content-Type"; @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { if (!(request instanceof MultiPartRequest)) { return super.performRequest(request, additionalHeaders); } else { return performMultiPartRequest(request, additionalHeaders); } } private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { for (String key : headers.keySet()) { httpRequest.setHeader(key, headers.get(key)); } } public HttpResponse performMultiPartRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createMultiPartRequest(request, additionalHeaders); addHeaders(httpRequest, additionalHeaders); addHeaders(httpRequest, request.getHeaders()); HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // TODO: Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); /* Make a thread safe connection manager for the client */ HttpClient httpClient = new DefaultHttpClient(httpParams); return httpClient.execute(httpRequest); } static HttpUriRequest createMultiPartRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: { // This is the deprecated way that needs to be handled for backwards // compatibility. // If the request's post body is null, then the assumption is that // the request is // GET. Otherwise, it is assumed that the request is a POST. byte[] postBody = request.getBody(); if (postBody != null) { HttpPost postRequest = new HttpPost(request.getUrl()); if (request.getBodyContentType() != null) postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); HttpEntity entity; entity = new ByteArrayEntity(postBody); postRequest.setEntity(entity); return postRequest; } else { return new HttpGet(request.getUrl()); } } case Method.GET: return new HttpGet(request.getUrl()); case Method.DELETE: return new HttpDelete(request.getUrl()); case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setMultiPartBody(postRequest, request); return postRequest; } case Method.PUT: { HttpPut putRequest = new HttpPut(request.getUrl()); if (request.getBodyContentType() != null) putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setMultiPartBody(putRequest, request); return putRequest; } // Added in source code of Volley libray. case Method.PATCH: { HttpPatch patchRequest = new HttpPatch(request.getUrl()); if (request.getBodyContentType() != null) patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); return patchRequest; } default: throw new IllegalStateException("Unknown request method."); } } /** * If Request is MultiPartRequest type, then set MultipartEntity in the * httpRequest object. * * @param httpRequest * @param request * @throws AuthFailureError */ private static void setMultiPartBody( HttpEntityEnclosingRequestBase httpRequest, Request<?> request) throws AuthFailureError { // Return if Request is not MultiPartRequest if (!(request instanceof MultiPartRequest)) { return; } MultipartEntity builder = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE); // MultipartEntityBuilder builder = MultipartEntityBuilder.create(); /* example for setting a HttpMultipartMode */ // builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); // Iterate the fileUploads // Map<String, File> fileUpload = ((MultiPartRequest) request) // .getFileUploads(); // for (Map.Entry<String, File> entry : fileUpload.entrySet()) { // builder.addPart(((String) entry.getKey()), new FileBody( // (File) entry.getValue())); // } ArrayList<Map<String, File>> fileUpload = ((MultiPartRequest) request) .getFileUploads(); for (int i = 0; i < fileUpload.size(); i++) { Map<String, File> fileMap = fileUpload.get(i); for (Map.Entry<String, File> entry : fileMap.entrySet()) { builder.addPart(((String) entry.getKey()), new FileBody( (File) entry.getValue())); } } // ContentType contentType = ContentType.create(HTTP.PLAIN_TEXT_TYPE, // HTTP.UTF_8); // Iterate the stringUploads Map<String, String> stringUpload = ((MultiPartRequest) request) .getStringUploads(); for (Map.Entry<String, String> entry : stringUpload.entrySet()) { try { // builder.addPart(((String) entry.getKey()), // new StringBody((String) entry.getValue(), contentType)); builder.addPart(entry.getKey(), new StringBody( entry.getValue(), Charset.forName(HTTP.UTF_8))); } catch (Exception e) { e.printStackTrace(); } } httpRequest.setEntity(builder); } }